Typical HAL ADC use cases for migration

This section provides information about typical HAL ADC architecture use cases for migration.

Use case: conversion by polling

Description of usage

Operation

HAL1

HAL2

Start conversion

Activate the ADC peripheral and start the conversion using:

  • HAL_ADC_Start() for the regular group.

  • HAL_ADCEx_InjectedStart for the injected group.

Activate the ADC peripheral and start the conversion using HAL_ADC_Start().

Note

From this point, the ADC internal analog hardware is enabled, inducing a slight current consumption.

Start the conversion with a trigger using:

  • HAL_ADC_REG_StartConv() for the regular group.

  • HAL_ADC_INJ_StartConv() for the injected group.

Note

The conversion trigger can be:

  • A software start: calls the function for each conversion.

  • From another peripheral (timer, for instance): calls the function once.

Calibration (optional)

  • Start calibration using HAL_ADCEx_Calibration_Start().

  • Get calibration value using HAL_ADCEx_Calibration_GetValue().

  • Set calibration value using HAL_ADCEx_Calibration_SetValue().

  • Calibrate the ADC using HAL_ADC_Calibrate().

  • Get calibration factor using HAL_ADC_GetCalibrationFactor().

  • Set calibration factor using HAL_ADC_SetCalibrationFactor().

Wait for conversion completion

Wait for ADC conversion completion using:

  • HAL_ADC_PollForConversion() for the regular group.

  • HAL_ADCEx_InjectedPollForConversion() for the injected group.

Note

For specific events (such as ADC_EOSMP_EVENT or ADC_AWD1_EVENT), use HAL_ADC_PollForEvent().

Poll for conversion completion using:

  • HAL_ADC_REG_PollForConv() for the regular group.

  • HAL_ADC_INJ_PollForConv for the injected group.

Note

For specific events (such as ADC_EOSMP_EVENT or ADC_AWD1_EVENT), use HAL_ADC_PollForEvent().

Retrieve conversion results

Retrieve conversion results using:

  • HAL_ADC_GetValue() for the regular group.

  • HAL_ADCEx_InjectedGetValue for the injected group.

Retrieve conversion results using:

  • HAL_ADC_REG_GetValue() for the regular group.

  • HAL_ADC_INJ_GetValue for the injected group.

Stop conversion

Stop potential ongoing conversions and disable the ADC peripheral using:

  • HAL_ADC_Stop() for the regular and injected groups.

  • HAL_ADCEx_RegularStop for the regular group.

  • HAL_ADCEx_InjectedStop for the injected group.

If the conversion trigger is not a software start (from another peripheral, such as a timer), stop the conversion using:

  • HAL_ADC_REG_StopConv() for the regular group.

  • HAL_ADC_INJ_StopConv for the injected group.

Stop the ADC using HAL_ADC_Stop().

Loop for multiple iterations

N/A

Multiple iterations for starting and stopping conversions are possible.

Warning

If multiple conversions are required, do not fully stop the ADC using the HAL_ADC_Stop() function.

Sequence diagram

ADC conversion by polling

@startuml

participant "Application" as App
participant "ADC" as ADC

App -> ADC: <font color=green><b>HAL_ADC_Start() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedStart()
App -> ADC: <font color=green><b>HAL_ADC_PollForConversion() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedPollForConversion()
App -> ADC: <font color=green><b>HAL_ADC_GetValue() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedGetValue()
App -> ADC: <font color=green><b>HAL_ADC_Stop() <font color=black>/ <font color=green><b>HAL_ADCEx_RegularStop() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedStop()

@enduml

Code snippet

HAL1

HAL2

Regular group use case

while(1)
{
  /* Start the ADC conversion */
  HAL_ADC_Start(&hadc1);

  /* Poll for the end of conversion */
  if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK)
  {
      /* Read the ADC value */
      adcValue = HAL_ADC_GetValue(&hadc1);
  }

  /* Stop the ADC conversion */
  HAL_ADC_Stop(&hadc1);

}

Regular group use case

/* Start the ADC  */
HAL_ADC_Start(&hadc1);
while(1)
{
  /* Start the ADC conversion */
  HAL_ADC_REG_StartConv(&hadc1);

  /* Poll for the end of conversion */
  if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK)
  {
      /* Read the ADC value */
      adcValue = HAL_ADC_GetValue(&hadc1);
  }

  /* Stop the ADC regular conversion */
  HAL_ADC_REG_StopConv(&hadc1);

}
/* Stop the ADC */
HAL_ADC_Stop(&hadc1);

Injected group use case

while(1)
{
  /* Start the ADC injected conversion */
  HAL_ADCEx_InjectedStart(&hadc1);

  /* Poll for the end of injected conversion */
  if (HAL_ADCEx_InjectedPollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK)
  {
      /* Read the ADC injected values */
      injectedValue1 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
      injectedValue2 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_2);
  }

  /* Stop the ADC injected conversion */
  HAL_ADCEx_InjectedStop(&hadc1);

}

Injected group use case

/* Start the ADC  */
HAL_ADC_Start(&hadc1);

while(1)
{
  /* Start the ADC conversion */
  HAL_ADC_INJ_StartConv(&hadc1);

  /* Poll for the end of injected conversion */
  if (HAL_ADC_INJ_PollForConv(&hadc1, HAL_MAX_DELAY) == HAL_OK)
  {
      /* Read the ADC injected values */
      injectedValue1 = HAL_ADC_INJ_GetValue(&hadc1, 1);
      injectedValue2 = HAL_ADC_INJ_GetValue(&hadc1, 2);
  }

  /* Stop the ADC injected conversion */
  HAL_ADC_INJ_StopConv(&hadc1);

}
/* Stop the ADC  */
HAL_ADC_Stop(&hadc1);

Key changes

  1. The split of the activate and start conversion functions.

  2. The split of the disable and stop conversion functions.

Use case: conversion by interruption

Description of usage

Operation

HAL1

HAL2

Start conversion

Activate the ADC peripheral and start conversions in interrupt mode using:

  • HAL_ADC_Start_IT() for the regular group.

  • HAL_ADCEx_InjectedStart_IT() for the injected group.

Activate the ADC peripheral and start conversions using HAL_ADC_Start().

Note

From this point, the ADC internal analog hardware is enabled, inducing a slight current consumption.

Start the conversion with a trigger using:

  • HAL_ADC_REG_StartConv_IT() for the regular group.

  • HAL_ADC_INJ_StartConv_IT() for the injected group.

Note

Conversion trigger can be:

  • A software start: calls the function for each conversion.

  • From another peripheral (timer, for instance): calls the function once.

Calibration (optional)

  • Start calibration using HAL_ADCEx_Calibration_Start().

  • Get calibration value using HAL_ADCEx_Calibration_GetValue().

  • Set calibration value using HAL_ADCEx_Calibration_SetValue().

  • Calibrate the ADC using HAL_ADC_Calibrate().

  • Get calibration factor using HAL_ADC_GetCalibrationFactor().

  • Set calibration factor using HAL_ADC_SetCalibrationFactor().

Conversion complete callback

Implement the callback using:

  • HAL_ADC_ConvCpltCallback() for the regular group, which is called when the conversion is complete.

  • HAL_ADCEx_InjectedConvCpltCallback() for the injected group, which is called when the conversion is complete.

Implement the callback using:

  • HAL_ADC_REG_UnitaryConvCpltCallback() for the regular group, which is called when the conversion is complete.

  • HAL_ADC_RegisterInjUnitaryConvCpltCallback() for the injected group, which is called when the conversion is complete.

Retrieve conversion results

Retrieve conversion results using:

  • HAL_ADC_GetValue() for the regular group.

  • HAL_ADCEx_InjectedGetValue for the injected group.

Retrieve conversion results using:

  • HAL_ADC_REG_GetValue() for the regular group.

  • HAL_ADC_INJ_GetValue for the injected group.

Stop conversion

Stop potential ongoing conversions and disable the ADC peripheral using:

  • HAL_ADC_Stop_IT() for the regular and injected group.

  • HAL_ADCEx_RegularStop_IT() for the regular group.

  • HAL_ADCEx_InjectedStop_IT() for the injected group.

If the conversion trigger is not a software start (such as from another peripheral like a timer), stop the conversion using:

  • HAL_ADC_REG_StopConv_IT() for the regular group.

  • HAL_ADC_INJ_StopConv_IT() for the injected group.

Stop the ADC using HAL_ADC_Stop().

Loop for multiple iterations

N/A

Multiple iterations for starting and stopping conversions are possible.

Warning

If multiple conversions are required, do not fully stop the ADC using the HAL_ADC_Stop() function.

Sequence diagram

ADC interruption mode

@startuml

participant "User application\n(thread mode)" as appli
participant "User application\n(handler mode)" as appli_IRQ
participant "<font color=green><b>HAL ADC</b></font>" as ADC
participant "System HW interruption" as interruption

group#Linen ADC operation

  appli->ADC : <font color=green><b>HAL_ADC_Start_IT() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedStart_IT()
  return

ADC->ADC : Enable ADC selected interruptions\nEnable ADC conversion trigger
interruption <[#purple]-x? : <font color=purple><b>ADC IRQ event
interruption -> appli_IRQ : ADCx_IRQHandler()
activate appli_IRQ #DarkSalmon
appli_IRQ -> ADC : HAL_ADC_IRQHandler()

return
ADC -> ADC : Clear flag

  ADC -> appli_IRQ: <font color=green><b>HAL_ADC_ConvCpltCallback() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedConvCpltCallback()
  return
  appli_IRQ->ADC : <font color=green><b>HAL_ADC_GetValue() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedGetValue()
  ADC --> appli_IRQ
  appli_IRQ -> interruption : (return from ISR)
  deactivate appli_IRQ
  appli->ADC : <font color=green><b>HAL_ADC_Stop_IT() <font color=black>/ <font color=blue><b>HAL_ADCEx_InjectedStop_IT()
  return

@enduml

Code snippet

HAL1

HAL2

Regular group use case

int main(void)
{
    // Add your Init and config code

    /* Start the ADC conversion in interrupt mode */
    HAL_ADC_Start_IT(&hadc1);

    // Wait flag end of conversion raised

    HAL_ADC_Stop_IT(&hadc1);

}

/* ADC conversion complete callback */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1)
    {
        /* Read the ADC value */
        adcValue = HAL_ADC_GetValue(hadc);
        /* Add your processing code here */
    }
}

/* ADC analog watchdog callback */
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
{
     /* Handle the analog watchdog event
        Add your processing code here  */
}

/* ADC interrupt handler */
void ADC1_IRQHandler(void)
{
    HAL_ADC_IRQHandler(&hadc1);
}

Regular group use case

int main(void)
{
    hal_status_t hal_status;

    // Add your Init and config code

    // Set your AWD thresholds using HAL_ADC_SetAnalogWDThresholds()

    /* Start the ADC conversion in interrupt mode */
    HAL_ADC_Start(&hadc1);
    while (1)
    {
        /* ========== ADC measurement ========== */
        hal_status |= HAL_ADC_REG_StartConv_IT_Opt(&hadc1, HAL_ADC_OPT_IT_REG_EOC | HAL_ADC_OPT_IT_AWD_1);

        // Wait flag end of conversion raised

        /* Stop the ADC conversion in interrupt mode */
        HAL_ADC_REG_StopConv_IT(&hadc1);
    }
    /* ADC stop */
    hal_status |= HAL_ADC_Stop(&hadc1);
}

/* ADC conversion complete callback */
void HAL_ADC_REG_UnitaryConvCpltCallback(hal_adc_handle_t *hadc)
{
   /* Read the ADC value */
   adcValue = HAL_ADC_REG_GetValue(hadc);

}

/* ADC analog watchdog callback */
void HAL_ADC_AnalogWD_OutOfWindowCallback(hal_adc_handle_t *hadc, hal_adc_awd_instance_t awd_instance)
{
    if (awd_instance == HAL_ADC_AWD_1)
    {
        // Handle the analog watchdog event
        // Add your processing code here
    }
}

/* ADC interrupt handler */
void ADC1_IRQHandler(void)
{
    HAL_ADC_IRQHandler(&hadc1);
}

Injected group use case

int main(void)
{
    // Add your Init and config code

    /* Start the ADC conversion in interrupt mode */
    HAL_ADCEx_InjectedStart_IT(&hadc1);

    // Wait flag end of conversion raised

    /* Stop  the ADC conversion in interrupt mode */
    HAL_ADCEx_InjectedStop_IT(&hadc1);

}

/* ADC conversion complete callback */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1)
    {
         /* Read the ADC injected values */
        injectedValue1 = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);
        injectedValue2 = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);
         /* Add your processing code here */
    }
}

/* ADC analog watchdog callback */
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1)
    {
        // Handle the analog watchdog event
        // Add your processing code here
    }
}

/* ADC interrupt handler */
void ADC1_IRQHandler(void)
{
    HAL_ADC_IRQHandler(&hadc1);
}

Injected group use case

int main(void)
{
    hal_status_t hal_status;

    // Add your Init and config code

    // Set your AWD thresholds using HAL_ADC_SetAnalogWDThresholds()

     /* Start the ADC conversion in interrupt mode */
    HAL_ADC_Start(&hadc1);
    while (1)
    {
        /* ========== ADC measurement ========== */
        hal_status |= HAL_ADC_INJ_StartConv_IT(&hadc1, HAL_ADC_OPT_IT_REG_EOC | HAL_ADC_OPT_IT_AWD_1);

        // Wait flag end of conversion raised

         /* Stop the ADC conversion in interrupt mode */
        HAL_ADC_INJ_StopConv_IT(&hadc1);
    }
     /* ADC stop */
    hal_status |= HAL_ADC_Stop(&hadc1);
}

 /* ADC conversion complete callback */
void HAL_ADC_RegisterInjUnitaryConvCpltCallback(hal_adc_handle_t *hadc)
{
    /* Read the ADC value */
   adcValue = HAL_ADC_INJ_GetValue (hadc,1);
    /* Add your processing code here */
}

 /* ADC analog watchdog callback */
void HAL_ADC_AnalogWD_OutOfWindowCallback(hal_adc_handle_t *hadc, hal_adc_awd_instance_t awd_instance)
{
    if (awd_instance == HAL_ADC_AWD_1)
    {
        // Handle the analog watchdog event
        // Add your processing code here
    }
}

 /* ADC interrupt handler */
void ADC1_IRQHandler(void)
{
    HAL_ADC_IRQHandler(&hadc1);
}

Key changes

  1. The split of the activate and start conversion functions in interrupt mode.

  2. The split of the disable and stop conversion functions in interrupt mode.

  3. In HAL2, use HAL_ADC_REG_StartConv_IT_Opt() instead of HAL_ADC_REG_StartConv_IT() to enable only specific interruptions, such as EOC and AWD1.

Related examples in HAL2

Example name

Brief

hal_adc_analog_watchdog

How to use the ADC with an ADC analog watchdog to monitor a channel and detect when the corresponding conversion data is outside the window thresholds.

hal_adc_single_conversion_trigger_sw_it

How to use the ADC to convert a single channel at each software request. The conversion is performed using the interrupt programming model.


Use case: conversion in DMA mode

Description of usage

Operation

HAL1

HAL2

Start conversion in DMA Mode

Activate the ADC peripheral and start conversions in DMA mode using HAL_ADC_Start_DMA(). Specify the buffer where the ADC data will be stored and the length of the buffer.

Activate the ADC peripheral and start conversions using HAL_ADC_Start().

Note

From this point, the ADC internal analog hardware is enabled, inducing a slight current consumption.

Start conversion with a trigger using HAL_ADC_REG_StartConv_DMA().

Note

The conversion trigger can be:

  • A software start: calls the function for each conversion.

  • From another peripheral (timer, for instance): calls the function once.

Calibration (optional)

  • Start calibration using HAL_ADCEx_Calibration_Start().

  • Get calibration value using HAL_ADCEx_Calibration_GetValue().

  • Set calibration value using HAL_ADCEx_Calibration_SetValue().

  • Calibrate the ADC using HAL_ADC_Calibrate().

  • Get calibration factor using HAL_ADC_GetCalibrationFactor().

  • Set calibration factor using HAL_ADC_SetCalibrationFactor().

DMA transfer complete callback

Implement the HAL_ADC_ConvCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

Implement the HAL_ADC_REG_DataTransferCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

DMA half-transfer callback

Implement the HAL_ADC_ConvHalfCpltCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Implement the HAL_ADC_REG_DataTransferHalfCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Retrieve conversion results

The conversion results are stored in the buffer specified in HAL_ADC_Start_DMA(). Process the data in the transfer complete and half-transfer complete DMA callbacks.

The conversion results are stored in the buffer specified in HAL_ADC_REG_StartConv_DMA(). Process the data in the transfer complete and half-transfer complete DMA callbacks.

Stop conversion

  • Stop potential ongoing conversions on the regular and injected ADC groups and disable the ADC peripheral using HAL_ADC_Stop_DMA().

  • Stop potential ongoing conversions on the regular ADC group and disable the ADC peripheral using HAL_ADCEx_RegularStop_DMA().

  • If the conversion trigger is not a software start (from another peripheral, such as a timer), stop the conversion using HAL_ADC_REG_StopConv_DMA().

  • Stop the ADC using HAL_ADC_Stop().

Loop for multiple iterations

N/A

Multiple iterations for starting and stopping conversions are possible.

Warning

If multiple conversions are required, do not fully stop the ADC using the HAL_ADC_Stop() function.

Sequence diagram

ADC data transfer in DMA mode

@startuml

participant "User application\n(thread mode)" as appli
participant "User application\n(handler mode)" as appli_IRQ
participant "<font color=green><b>HAL ADC</b></font>" as ADC
participant "<font color=green><b>HAL DMA</b></font>" as DMA
participant "System HW interruption" as interruption

group#Bisque #Linen ADC operation
appli->ADC : HAL_ADC_Start_DMA()
note right
From this point, the ADC internal analog hardware is
enabled (inducing a slight current consumption) and
conversion in DMA mode starts.
end note
return
appli->ADC : HAL_ADCEx_Calibration_Start()
return

ADC->ADC : Enable ADC selected interruptions\nEnable DMA request\nEnable ADC conversion trigger
interruption <[#purple]-x? : <font color=purple><b>DMA IRQ event\n(transfer complete)
interruption -> appli_IRQ : DMAx_IRQHandler()
activate appli_IRQ #DarkSalmon
appli_IRQ -> DMA : HAL_DMA_IRQHandler()
DMA -> DMA : Clear flag
DMA->ADC : Callback function pointer
ADC -> appli_IRQ: HAL_ADC_ConvCpltCallback()
appli_IRQ -> appli_IRQ : User application processing
appli_IRQ -> interruption : (Return from ISR)
deactivate appli_IRQ

appli->ADC : HAL_ADC_Stop_DMA()
return
end

@enduml

Code snippet

HAL1

HAL2

#define ADC_BUFFER_SIZE 10
uint32_t adcBuffer[ADC_BUFFER_SIZE];

int main(void)
{
    // Add your Init and config code

    if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcBuffer, ADC_BUFFER_SIZE) != HAL_OK)
    {
        /* Start Error */
        Error_Handler();
    }

}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    /* Stop ADC conversion and DMA transfer */
    HAL_ADC_Stop_DMA(hadc);
    /* Handle the completed conversion data */
    for (int i = 0; i < ADC_BUFFER_SIZE; i++)
    {
      /* Process adcBuffer[i] */
    }
}
#define ADC_BUFFER_SIZE 10
uint32_t adcBuffer[ADC_BUFFER_SIZE];
/* Loop for Multiple Iterations  var */
uint32_t TestLoop = 3;

int main(void)
{
    // Add your Init and config code

    /* ADC activation */
    HAL_ADC_Start(&hadc1);

    while (TestLoop != 0)
    {
       /* ADC with DMA measurement */
      if (HAL_ADC_REG_StartConv_DMA(&hadc1, (uint32_t*)adcBuffer, ADC_BUFFER_SIZE) != HAL_OK)
      {
          /* Start Error */
          Error_Handler();
      }
      /* Wait time for ADC conversion */
      HAL_Delay(5);
      TestLoop--;
    }
    /* Stop ADC */
    HAL_ADC_Stop();
}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_REG_DataTransferCpltCallback(hal_adc_handle_t *hadc)
{
    /* Stop ADC conversion and DMA transfer */
    HAL_ADC_REG_StopConv_DMA(hadc);
    /* Handle the completed conversion data */
    for (int i = 0; i < ADC_BUFFER_SIZE; i++)
    {
      /* Process adcBuffer[i] */
    }
}

Key changes

  1. The split of the activate and start conversion in DMA mode functions.

  2. The split of the disable and stop conversion in DMA mode functions.


Use case: conversion in multimode DMA

Description of usage

HAL1

HAL2

Start conversion in multimode DMA

Activate the ADC peripheral and start the conversion in multimode DMA using HAL_ADCEx_MultiModeStart_DMA(). Specify the buffer where the ADC data is stored and its length.

Activate the ADC peripheral and start the conversion using HAL_ADC_MM_Start().

Note

From this point, the ADC internal analog hardware is enabled, inducing a slight current consumption.

Start the conversion with a trigger using:

  • HAL_ADC_MM_REG_StartConv_DMA(): single DMA channel for all ADC instances.

  • HAL_ADC_MM_REG_StartConvM_DMA(): separate DMA channel for each ADC instance.

Note

The conversion trigger can be:

  • A software start: calls the function for each conversion.

  • From another peripheral (timer, for instance): calls the function once.

Calibration (optional)

  • Start calibration using HAL_ADCEx_Calibration_Start().

  • Get calibration value using HAL_ADCEx_Calibration_GetValue().

  • Set calibration value using HAL_ADCEx_Calibration_SetValue().

  • Calibrate each ADC using HAL_ADC_Calibrate() or all using HAL_ADC_MM_Calibrate().

  • Get calibration factor using HAL_ADC_GetCalibrationFactor().

  • Set calibration factor using HAL_ADC_SetCalibrationFactor().

DMA transfer complete callback

Implement the HAL_ADC_ConvCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

Implement the HAL_ADC_REG_DataTransferCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

DMA half-transfer callback

Implement the HAL_ADC_ConvHalfCpltCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Implement the HAL_ADC_REG_DataTransferHalfCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Retrieve conversion results

Use HAL_ADCEx_MultiModeGetValue() to retrieve the conversion results. This function can be called within the DMA transfer complete callback to get the combined result of the master and slave ADCs.

The conversion results are stored in the buffer specified in HAL_ADC_REG_StartConv_DMA(). Process the data in the DMA transfer complete and half-transfer complete callbacks.

Stop conversion

Stop potential ongoing conversions on the regular and injected groups and disable the ADC peripheral using HAL_ADCEx_MultiModeStop_DMA().

If the conversion trigger is not a software start (such as from another peripheral like a timer), stop the conversion using HAL_ADC_MM_REG_StopConv_DMA().

Stop the ADC using HAL_ADC_MM_Stop().

Loop for multiple iterations

N/A

Multiple iterations for starting and stopping conversions are possible.

Warning

If multiple conversions are required, do not fully stop the ADC using the HAL_ADC_Stop() function.

Sequence diagram

ADC data transfer in multimode DMA

@startuml

participant "User application\n(thread mode)" as appli
participant "User application\n(handler mode)" as appli_IRQ
participant "<font color=green><b>HAL ADC</b></font>" as ADC
participant "<font color=green><b>HAL DMA</b></font>" as DMA
participant "System HW interruption" as interruption

group#Bisque #Linen ADC operation
appli->ADC : HAL_ADCEx_MultiModeStart_DMA()
note right
From this point, the ADC internal analog hardware is
enabled (inducing a slight current consumption) and
conversion in DMA mode starts.
end note
return
appli->ADC : HAL_ADCEx_Calibration_Start()
return

ADC->ADC : Enable ADC selected interruptions\nEnable DMA request\nEnable ADC conversion trigger
interruption <[#purple]-x? : <font color=purple><b>DMA IRQ event\n(transfer complete)
interruption -> appli_IRQ : DMAx_IRQHandler()
activate appli_IRQ #DarkSalmon
appli_IRQ -> DMA : HAL_DMA_IRQHandler()
DMA -> DMA : Clear flag
DMA->ADC : Callback function pointer
ADC -> appli_IRQ: HAL_ADC_ConvCpltCallback()
appli_IRQ -> appli_IRQ : User appli processing
appli_IRQ -> interruption : (Return from ISR)
deactivate appli_IRQ

appli->ADC : HAL_ADCEx_MultiModeStop_DMA()
return
end

@enduml

Code snippet

HAL1

HAL2

uint32_t adcBuffer[2];

int main(void)
{
    // Add your Init and config code

    if (HAL_ADCEx_MultiModeStart_DMA(&hadc_master, (uint32_t*)adcBuffer, 2) != HAL_OK)
    {
        /* Start Error */
        Error_Handler();
    }

}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1)
    {
         /* Process the ADC conversion results stored in adcBuffer */
        uint32_t adcValue1 = adcBuffer[0];
        uint32_t adcValue2 = adcBuffer[1];

         /* Example: Print the ADC values (you can replace this with your own processing code) */
        printf("ADC1 Value: %lu, ADC2 Value: %lu\n", adcValue1, adcValue2);

         /* Stop the ADC conversion */
        if (HAL_ADCEx_MultiModeStop_DMA(&hadc_master) != HAL_OK)
        {
             /* Stop Error */
            Error_Handler();
        }
    }
}
uint32_t adcBuffer[2];
/* Loop for Multiple Iterations  var */
uint32_t TestLoop = 3;

int main(void)
{
    // Add your Init and config code

    /* ADC activation */
    HAL_ADC_MM_Start(&hadc_master);

    while (TestLoop != 0)
    {
       /* ADC with DMA measurement */
      if (HAL_ADC_MM_REG_StartConv_DMA(&hadc_master, (uint32_t*)adcBuffer, ADC_BUFFER_SIZE) != HAL_OK)
      {
          /* Start Error */
          Error_Handler();
      }
      /* Wait time for ADC conversion */
      HAL_Delay(5);
      TestLoop--;
    }
    /* Stop ADC */
    HAL_ADC_MM_Stop();
}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_REG_DataTransferCpltCallback(hal_adc_handle_t *hadc)
{
    if (hadc->Instance == ADC1)
    {
         /* Process the ADC conversion results stored in adcBuffer */
        uint32_t adcValue1 = adcBuffer[0];
        uint32_t adcValue2 = adcBuffer[1];

         /* Example: Print the ADC values (you can replace this with your own processing code) */
        printf("ADC1 Value: %lu, ADC2 Value: %lu\n", adcValue1, adcValue2);

         /* Stop the ADC conversion */
        if (HAL_ADC_MM_REG_StopConv_DMA(&hadc_master) != HAL_OK)
        {
             /* Stop Error */
            Error_Handler();
        }
    }
}

Key changes

  1. The split of the activate and start conversion in multimode DMA functions.

  2. The split of the disable and stop conversion in multimode DMA functions.

Related examples in HAL2

Example name

Brief

hal_adc_multimode_simultaneous_dma_multi_buffers

How to convert two channels simultaneously using two ADC instances (master and slave). Conversions are triggered by a timer and data are transferred with DMA using one buffer per ADC. This example is based on the ADC HAL API.